package com.wchat.controller;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.wchat.configurer.RedisPoolConfig;
import com.wchat.dataobject.BlackList;
import com.wchat.dataobject.UserEntity;
import com.wchat.dto.*;
import com.wchat.enums.Log;
import com.wchat.enums.ResultEnum;
import com.wchat.exceptions.ServiceException;
import com.wchat.po.BlackListIdParam;
import com.wchat.po.MyMessage;
import com.wchat.po.User;
import com.wchat.po.addInBlackList;
import com.wchat.repository.BlackListRepository;
import com.wchat.repository.MyMessageRepository;
import com.wchat.repository.UserRepository;
import com.wchat.service.AuthUtilService;
import com.wchat.service.SearchAroundService;
import com.wchat.service.UserService;
import com.wchat.service.WechatService;
import com.wchat.utils.CommonUtil;
import com.wchat.utils.ResultVoUtils;
import com.wchat.vo.*;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.Jwts;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.scheduling.annotation.Async;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.swing.text.html.parser.Entity;
import javax.transaction.Transactional;
import javax.ws.rs.POST;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@Slf4j
@RequestMapping("/user")
@Api(value = "用户中心")
public class UserController {

    @Autowired private UserService userService;
    @Autowired private SearchAroundService  searchAroundService;
    @Autowired private UserRepository userRepository;
    @Autowired private BlackListRepository blackListRepository;
    @Autowired private MyMessageRepository myMessageRepository;
    @Autowired private AuthUtilService authUtilService;

    /**
     * 用户通过手机号注册
     * @param userRegisterVo
     * @param request
     * @return
     */
    @ResponseBody
    @PostMapping("/register")
    @ApiOperation(value = "用户通过手机号注册",notes = "用户手机号注册,验证码只能使用一次")
    public ResultVo<UserRegisterDTO> userRegisterByPhoneNumber(@RequestBody UserRegisterVo userRegisterVo,HttpServletRequest request){
        return ResultVoUtils.success(userService.userRegisterByPhone(userRegisterVo.getPhoneNumber(),userRegisterVo.getVerifyCode(),userRegisterVo.getPassword(),request));
    }

    /**
     * 用户通过手机号登录
     * @param userLoginVo
     * @param request
     * @return
     */
    @Log("用户登录")
    @ResponseBody
    @PostMapping("/userLoginByPhone")
    @ApiOperation(value = "用户通过手机号登录",notes = "用户登录时候统一入口 如果该用户没有注册 直接进行绑定注册 返回登录信息 ，如果已经注册 则绑定后登录，如果已经绑定 则直接登录")
    public ResultVo<UserLoginDTO> userLoginByPhone(@RequestBody UserLoginVo userLoginVo, HttpServletRequest request){
       // ResultVo<UserLoginDTO> userLoginDTOResultVo = ResultVoUtils.success(userService.userLoginByPhone(userLoginVo,request));
        HttpSession session = request.getSession();
        UserEntity userEntity = userRepository.findByPhoneNumber(userLoginVo.getPhoneNumber());
        session.setAttribute("userId",userEntity.getUserId());
        userRepository.updateUser(userLoginVo.getNickName(),userLoginVo.getGender(),userLoginVo.getHeadImage(),
                userLoginVo.getOpenid(),userLoginVo.getCity(),userLoginVo.getProvince(),userLoginVo.getCountry(),userEntity.getUserId());
        ResultVo<UserLoginDTO> userLoginDTOResultVo = ResultVoUtils.success(userService.userLoginByPhone(userLoginVo,request));
        return userLoginDTOResultVo;
    }

    /**
     * 查找附近的人
     * @param searchAroudVo  840317
     * @return
     */
    @Log("查找附近的人呢")
    @ResponseBody
    @PostMapping("/search")
    @ApiOperation(value = "定位并查找附近的人",notes = "通过定位之后 查找附近的人 前端传入经度和纬度")
    public ResultVo<List<UserEntity>> searchAroundUser(@RequestBody SearchAroudVo searchAroudVo,HttpServletRequest request){
//        HttpSession session = request.getSession();
//        if(session.getAttribute("userId") == null){
//
//            return ResultVoUtils.error(401,"亲，请先登录在操作");
//        }
        return ResultVoUtils.success(searchAroundService.searchAround(searchAroudVo.getUserId()));
    }

    /**
     * 用户退出登录
     * @param request
     * @param session
     * @return
     */
    @ResponseBody
    @PostMapping("/logout")
    @ApiOperation(value = "退出登录",notes = "用户退出登录")
    public ResultVo<String> logout(HttpServletRequest request,HttpSession session){
        Object userId = request.getSession().getAttribute("userId");
        try (Jedis jedis = RedisPoolConfig.getJedis()){
            StringBuilder builder = new StringBuilder("user_token:user_");
            jedis.del(String.valueOf(builder.append(userId)));
        }
        return ResultVoUtils.success("退出登录");
    }

    /**
     * 忘记密码---修改密码
     * @param request
     * @param session
     * @return
     */
    @ResponseBody
    @PostMapping("/forgetPass")
    @ApiOperation(value = "忘记密码",notes = "忘记密码 通过手机号和验证码操作")
    public ResultVo<String> forgetPass(@RequestBody ForgetPasswordVo forgetPasswordVo, HttpServletRequest request, HttpSession session){
//        if(session.getAttribute("userId") == null){
//            return ResultVoUtils.error(401,"亲，请先登录在操作");
//        }
        userService.forgetPass(forgetPasswordVo);
        return ResultVoUtils.success("修改成功");
    }

    @RequestMapping("/websocket/{name}")
    public String webSocket(@PathVariable String name,Model model){
        try{
            log.info("跳转到websocket的页面上");
            model.addAttribute("username",name);
            return "websocket";
        }
        catch (Exception e){
            log.info("跳转到websocket的页面上发生异常，异常信息是："+e.getMessage());
            return "error";
        }
    }

    /**
     * 添加关注
     * @param
     * @param
     * @return
     */
    @PostMapping("/addfollow")
    @ApiOperation(value = "添加关注",notes = "添加关注")
    public ResultVo<FollowCountsDto> addFollow(@RequestBody AddFollowVo addFollowVo,HttpSession session){
//        if(session.getAttribute("userId") == null){
//            return ResultVoUtils.error(401,"亲，请先登录在操作");
//        }
        Long followCount = userService.addFollow(addFollowVo.getUserIdA(),addFollowVo.getUserIdB());
        if(followCount >= 10){
            return ResultVoUtils.error(405,"对不起，您已经到达关注上限");
        }
        FollowCountsDto followCountsDto = new FollowCountsDto();
        followCountsDto.setFollowCounts(followCount);
        return ResultVoUtils.success(followCountsDto);
    }

    /**
     * 取消关注
     * @param
     * @param
     * @return
     */
    @PostMapping("/canclefollow")
    @ApiOperation(value = "取消关注",notes = "取消关注")
    public ResultVo<String> addFollow(@RequestBody cancelFollowVo cancelFollowVo,HttpSession session){
//        if(session.getAttribute("userId") == null){
//            return ResultVoUtils.error(401,"亲，请先登录在操作");
//        }
        userService.cancleFollow(cancelFollowVo.getUserIdA(),cancelFollowVo.getUserIdB());
        return ResultVoUtils.success("取消关注成功");
    }

    /**
     * 获取关注列表
     * @param
     * @param
     * @returnu
     */
    @PostMapping("/followList")
    @ApiOperation(value = "获取关注列表",notes = "获取列表关注")
    public ResultVo<List<Entity>> addFollow(@RequestBody UserIdVo userIdVo,HttpSession session) {
//        if(session.getAttribute("userId") == null){
//            return ResultVoUtils.error(401,"亲，请先登录在操作");
//        }
        return ResultVoUtils.success(userService.followList(userIdVo.getUserId()));
    }

    /**
     * 获取微信openid
     * @param code
     * @return
     */
    @ApiOperation(value = "微信小程序获取openId", notes = "微信小程序获取openId")
    @RequestMapping(value="/getOpenId",method = RequestMethod.POST)
    @ResponseBody
    public ResultVo<Map<String, Object>> getOpenId(@RequestBody MiniProgremCodeParam code){
        Map<String, Object> map = new HashMap<String, Object>();
        String status = "1";
        String msg = "ok";
        String WX_URL = "https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code";
        try {
            String value = code.getCode();
            log.info("{code}===={}", value);
            log.info("【code】===============》{}",code);
            if(StringUtils.isBlank(value) || value == ""){
                status = "0";//失败状态
                msg = "code为空";
            }else {
                String requestUrl = WX_URL.replace("APPID", WechatService.miniProgremAppId).
                        replace("SECRET", WechatService.miniProgremSecret).replace("JSCODE", value).
                        replace("authorization_code", WechatService.miniProgremGrantType);
                log.info("【requestUrl】==================》{}", requestUrl);
                // 发起GET请求获取凭证
                JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);
                if (jsonObject != null) {
                    try {
                        map.put("openid", jsonObject.getString("openid"));
                        map.put("session_key", jsonObject.getString("session_key"));
                        //  获取unionid 如果该小程序已经和公众号已经绑定 就不需要通过复杂的方式来获取unionid 直接通过前端传过来的code进行获取
//                        map.put("unionid",jsonObject.getString("unionid"));
                        log.info("【openid】{}",map.get("openid").toString());
                        if(StringUtils.isBlank(map.get("openid").toString())){
                            throw new ServiceException(ResultEnum.USER_UNIONID_PARAMETER_ERRORS.getCode(),
                                    ResultEnum.USER_UNIONID_PARAMETER_ERRORS.getValue()); //  用户获取 unionId错误
                        }
                        List<UserEntity> user = userRepository.findByopenid(map.get("openid").toString());
                        if(CollectionUtils.isEmpty(user) || (user.get(0).getIsNew() == 1) ){
                            map.put("isNew",1); //  1 代表新用户
                        }else {
                            map.put("isNew", 0); //  0 表示非新用户
                        }
                    } catch (JSONException e) {
                        // 获取token失败
                        status = "0";
                        msg = "code无效";
                    }
                } else {
                    status = "0";
                    msg = "code无效";
                }
            }
            map.put("status", status);
            map.put("msg", msg);
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            return ResultVoUtils.error(5003,"亲，请联系管理员");
        }
        return ResultVoUtils.success(map);

    }

    /**
     * 用户登录成功后需要添加经度和纬度到redis中
     * @param postionParam
     * @return
     */
    @ApiOperation(value = "获取用户经度和纬度", notes = "获取用户经度和纬度")
    @RequestMapping(value="/addUserPosition",method = RequestMethod.POST)
    @ResponseBody
    public ResultVo addUserPosition(@RequestBody UserPostionParamVo postionParam) {


        Jedis jedis = RedisPoolConfig.getJedis();
        try {
            jedis.geoadd(String.valueOf(postionParam.getGender()),     // 根据性别来添加到到redis 以后可以通过性别来查找不同的附近的人
                    Double.valueOf(postionParam.getLongitude() == null ? 0L : Double.valueOf(postionParam.getLongitude())),
                    Double.valueOf(postionParam.getLatitude() == null ? 0L : Double.valueOf(postionParam.getLatitude())),
                    String.valueOf(postionParam.getUserId()));
            int result = userRepository.updateUserInfoByUserId(postionParam.getLongitude(), postionParam.getLatitude(), postionParam.getGender(), postionParam.getUserId());
            if (result >= 1) {
                return ResultVoUtils.success("添加经度和纬度成功");
            }
            return ResultVoUtils.error(5002, "添加经度和纬度失败 请联系管理员");
        }finally {
            if(jedis !=  null);
                log.info("【关闭redis】");
                jedis.close();
            }
        }


    /**
     * 添加用户黑名单
     * @param addInBlackList
     * @return
     */
    @PostMapping("/addInBlackList")
    @ApiOperation(notes = "添加某用户到黑名单",value = "添加用户到黑名单列表")
    public ResultVo addInBlackList(@RequestBody addInBlackList addInBlackList,HttpSession session){
//        if(session.getAttribute("userId") == null){
//            return ResultVoUtils.error(401,"亲，请先登录在操作");
//        }
        if (addInBlackList.getBlackedId() != null && addInBlackList.getUserId() != null) {
            if(checkUserIsValid(addInBlackList.getUserId()) && checkUserIsValid(addInBlackList.getBlackedId())) {
                BlackList blackList = new BlackList();
                blackList.setBlackId(addInBlackList.getBlackedId());
                blackList.setUserId(addInBlackList.getUserId());
                blackListRepository.save(blackList);
                return ResultVoUtils.success("添加成功");
            }
        }
        return ResultVoUtils.error(5001,"添加失败，请联系管理员");
    }

    private boolean checkUserIsValid(int userId){
        if(userRepository.findOne(userId) != null);
        return true;
    }

    /**
     * 获取我的消息列表
     * @paramList
     * @return
     */
    @PostMapping("/myMessages")
    @ApiOperation(notes = "获取我的消息，未读消息",value = "获取我的消息")
    public ResultVo<List<MyMessageDTO>> getMyMessage(@RequestBody MyMessage myMessage){
          if(myMessage.getUserId() == null){
              return ResultVoUtils.error(5002,"获取我的消息列表失败");
          }
             //  此处就不联表查询了 能坑一个是一个   消息列表
            List<com.wchat.dataobject.MyMessage> myMessageDTOList = myMessageRepository.findByUserId(myMessage.getUserId());
            List<MyMessageDTO> myMessageDTOS = new ArrayList<>();

        for (int i = 0; i < myMessageDTOList.size(); i++) { //  遍历消息列表
                MessageContent messageContent = new MessageContent();

                messageContent.setContent(myMessageDTOList.get(i).getMessageContent());   //  消息内容 多条消息

                String formats = "yyyy-MM-dd HH:mm:ss";
                String date = new SimpleDateFormat(formats, Locale.CHINA).format(new Date(myMessageDTOList.get(i).getDate().getTime()));
                messageContent.setDate(date);  //  时间格式化
                UserEntity fromUser = userRepository.findOne(myMessageDTOList.get(i).getFromUserId());
                String headImage = fromUser.getHeadImage(); // 获取发送者头像

                Integer fromUserId = fromUser.getUserId();
                messageContent.setFromUserCuteName(fromUser.getCuteName());
                messageContent.setFromUserHeadImage(headImage);
                messageContent.setFromUserId(fromUserId);
                messageContent.setUnReadNum(myMessageRepository.getUnReadMessageCount(fromUserId));
                MyMessageDTO messageDTO = new MyMessageDTO();
                messageDTO.setContent(messageContent);
                myMessageDTOS.add(messageDTO);
        }

//              messageDTO.setUserID(myMessage.getUserId());

            String cuteName = userRepository.findOne(myMessage.getUserId()).getCuteName();
            Jedis jedis =  RedisPoolConfig.getJedis();

          return ResultVoUtils.success(myMessageDTOS);
    }



    @PostMapping("/deleteListOf")
    @ApiOperation(notes = "删除列表中用户",value = "删除列表中用户")
    public ResultVo addInBlackList(@RequestBody BlackListIdParam blackListIdParam, HttpSession session){
//        if(session.getAttribute("userId") == null){
//            return ResultVoUtils.error(401,"亲，请先登录在操作");
//        }
        if (blackListIdParam.getBlackListId() == null){
            throw new ServiceException(ResultEnum.PARAM_ERROR.getCode(),ResultEnum.PARAM_ERROR.getValue());
        }
        myMessageRepository.delete(blackListIdParam.getBlackListId());
        return ResultVoUtils.success("删除完成");
    }

    @PostMapping("/getUserInfo")
    @ApiOperation(notes = "获取用户个人信息",value = "获取用户个人信息")
    public ResultVo<UserEntity> getUserInfo(@RequestBody UserIdVo userIdVo) {
        if(userIdVo == null){
            throw new ServiceException(ResultEnum.CURRENT_USER_NULL.getCode(),ResultEnum.CURRENT_USER_NULL.getValue());

        }
       return ResultVoUtils.success(userRepository.findOne(userIdVo.getUserId()));

    }



    @PostMapping("/loginStatus")
    @ApiOperation(notes = "判断用户是否登录",value = "通过token判断使用是否登录")
    public ResultVo<UserEntity> loginStatus(@RequestBody UserToken userToken) {
        if(StringUtils.isNotBlank(userToken.getToken())) {
           AuthUtilService.AuthInfo userInfo =  authUtilService.decryptFromJwt(userToken.getToken());
           if(userInfo != null) {
               int userId = userInfo.userId;//  获取到用户id
               return ResultVoUtils.success(userRepository.findOne(userId));
           }throw  new ServiceException(ResultEnum.NOT_LOGIN_STATUS.getCode(),ResultEnum.NOT_LOGIN_STATUS.getValue());

        }throw new ServiceException(ResultEnum.USER_TOKEN_IS_NULL.getCode(),ResultEnum.USER_TOKEN_IS_NULL.getValue());


    }


    @Log("测试注解是否好使?")
    @PostMapping("/test")
    @ApiOperation(notes = "测试注解是否好使",value = "测试注解是否好使")
    public ResultVo<Map<String,String>> testController(@RequestParam String name,HttpServletRequest request){
           Map<String,String> map  = new HashMap<>();
           map.put("name",request.getRequestURI());
           map.put("age","53");
           map.put("我的真名是",name);
           log.info("test9876543d");
           log.warn("ffsfsfsdfsdffgg");
        return ResultVoUtils.success(map);
    }



    @Log("test2")
    @PostMapping("/test2")
    @ApiOperation(notes = "测试",value = "测试?")
    public ResultVo test2Controller(HttpServletRequest request) {
        com.wchat.dataobject.MyMessage myMessage = new com.wchat.dataobject.MyMessage();
        myMessage.setDate(new Date());
        myMessage.setFromUserId( 12);
        myMessage.setMessageContent("cacacacacaacacac");
        myMessage.setUnReadNum(1);
        myMessage.setUserId(123);
        myMessageRepository.save(myMessage);
        return ResultVoUtils.success();
    }





}
